/*
 * @Author       : super-J
 * @Date         : 2022-06-18 15:40:08
 * @LastEditTime : 2022-06-20 09:11:22
 * @LastEditors  : super-J
 * @Description  : 
 */
import { Component, ComponentProps, ReactNode } from "react";
import { View, Text } from "@tarojs/components";
import "./index.scss";
import Taro from "@tarojs/taro";
import classNames from "classnames";

export interface SlideMenu extends CommonProps {
    content: string | ReactNode;
    onClick?(e?:any,index?: number, option?: SlideMenu,): void
}
export interface LGSlideProps extends CommonProps {
    slideMenu: SlideMenu[],//选项的菜单栏
    canSlide?: boolean, //是否能滑动

    slidesCho?: boolean;//仅仅在有LGSlides的组件包裹下使用

    onMove?(moveLength?: number, direction?: number, slideMoveMaxNum?: number): void;//moveLength:移动的距离| direction:移动的方向| slideMoveMaxNum:最大移动距离
    onMoveEnd?(moveLength?: number, direction?: number, slideMoveMaxNum?: number): void;//moveLength:移动的距离| direction:移动的方向| slideMoveMaxNum:最大移动距离
}
export interface LGSlideState {
    slideMoveNum: number;
}
export interface CommonProps {
    className?: string;
    style?: React.CSSProperties
    onClick?(): void
    children?: ReactNode
}
export class LGSlide extends Component<LGSlideProps, LGSlideState> {
    private startX: number;
    private endX: number;
    private slideMoveMaxNum: number;
    private slideMoveLength: number;
    private direction: number;
    private isOpen: boolean;
    constructor(props) {
        super(props);
        this.onStart = this.onStart.bind(this);
        this.onMove = this.onMove.bind(this);
        this.onEnd = this.onEnd.bind(this);
        this.startX = 0;//手指开始触摸的X轴坐标
        this.endX = 0;//手指结束触摸的X轴坐标
        this.slideMoveMaxNum = 0;//滑块能移动的最大距离
        this.slideMoveLength = 0;//滑块跟随手指移动的距离
        this.direction = -1;//滑块跟随手指移动的距离
        this.state = {
            slideMoveNum: 0,
        }
    }
    // 组件的默认props
    static defaultProps: LGSlideProps = {
        slideMenu: [{ content: '其他操作', }],
        canSlide: true
    }
    UNSAFE_componentWillReceiveProps(nextProps: LGSlideProps) {
        if (nextProps.slideMenu != this.props.slideMenu) { this.queryDocMenuOptionsWith(() => { this.switchSlideState(this.isOpen); }) }
        if (nextProps.slidesCho != this.props.slidesCho) { this.switchSlideState(nextProps.slidesCho); }
    }
    switchSlideState(isOpen) {
        if (isOpen) {
            this.openSlide();
        } else {
            this.closeSlide();
        }

    }
    componentDidMount() {
        this.queryDocMenuOptionsWith()
    }
    queryDocMenuOptionsWith(func?: any) {
        setTimeout(() => {
            let query = Taro.createSelectorQuery().in(this);
            query.selectAll(".lg_LGSlide_container_options")
                .boundingClientRect((res) => {
                    if (!res) { return };
                    let maxMoveLength = res[0].width;
                    this.slideMoveMaxNum = maxMoveLength;
                    func && func()
                })
                .exec(() => { });
        }, 200);
    }

    onStart(event) {
        this.props.onClick && this.props.onClick();
        this.startX = event.changedTouches[0].screenX || event.changedTouches[0].pageX;
    }
    onMove(event) {
        if (!this.props.canSlide) { return; }
        // 手指点击时的X坐标
        let startX = this.startX;
        // 滑动的到左边的最大距离
        let slideMoveMaxNum = this.slideMoveMaxNum;
        // 手指横滑动时的X坐标
        let eventMoveX = event.changedTouches[0].screenX || event.changedTouches[0].pageX;
        let moveLength = eventMoveX - startX;
        if (Math.abs(moveLength) <= 10 || (moveLength > 15 && !this.isOpen)) { return }
        if (this.state.slideMoveNum > 0) { this.closeSlide(); return }
        let direction = moveLength > 0 ? +1 : -1;
        if (Math.abs(moveLength) >= Math.abs(slideMoveMaxNum)) {
            moveLength = direction * slideMoveMaxNum
        };
        this.slideMoveLength = moveLength;
        this.direction = direction;
        this.props.onMove && this.props.onMove(moveLength, direction, slideMoveMaxNum)
        this.setState({ slideMoveNum: moveLength })

    }
    openSlide() {
        if (this.props.canSlide) {
            this.isOpen = true
            this.setState({ slideMoveNum: -1 * this.slideMoveMaxNum })
        }
    }
    closeSlide() {
        if (this.props.canSlide) {
            this.isOpen = false
            this.setState({ slideMoveNum: 0 })
        }
    }
    onEnd(event) {
        if (Math.abs(this.slideMoveLength) <= 10) { return }
        let direction = this.direction;
        if (direction < 0) { this.openSlide(); } else { this.closeSlide() }
        this.props.onMoveEnd && this.props.onMoveEnd(this.slideMoveLength, this.direction, this.slideMoveMaxNum)
    }
    render() {
        const { state, props } = this;

        return (
            <View
                className={classNames('lg_LGSlide_container', props.className)}
                style={props.style}
                onTouchStart={this.onStart}
                onTouchMove={this.onMove}
                onTouchEnd={this.onEnd}
                onClick={this.props.onClick}>
                <View
                    className="lg_LGSlide_container_children"
                    style={{ transform: "translateX(" + state.slideMoveNum + "px)" }}>
                    {props.children}
                    <View className="lg_LGSlide_container_options" >
                        {props.slideMenu.map((o, i) => {
                            let optionsItem = classNames('lg_LGSlide_container_options_item', o.className)
                            return (
                                <View
                                    className={optionsItem}
                                    style={o.style}
                                    onClick={(e) => {
                                        this.closeSlide();
                                        o.onClick && o.onClick(e,i, o);
                                    }}
                                    key={'lg_LGSlide_container_options_item_' + i}>
                                    {o.content}
                                </View>
                            );
                        })}
                    </View>
                </View>
            </View>
        );
    }
}


